package base.patterns.operation;

import base.patterns.delegate.Delegate.Slot;
import base.value.Value;


public class OperationBuilder<Result, Param> {

	private Function<Result, Param> o;
	
	public Value.String name = new Value.String();

	public OperationBuilder(){
		this(null);
	}
	
	public OperationBuilder(Function<Result, Param> o){
		this.o = o;
	}
	
	public Result execute(Param par){
		return this.o.call(par);
	}
	
	public void operation(Function<Result, Param> function) {
		o = function;
	}
	
	public void parametr(Function<?, Param> function) {
		o = OperationBuilder.prepareParam(function, o);
	}
	
	public void result(Function<?, Result> function) {
		o = OperationBuilder.prepareResult(o, function);
	}
	
	public Slot<Result, Param> build() {
		return new Slot<Result, Param>(o);
	}
	
	public static<Result, Param> Function<Result, Param> resultOperation(
			final Function<Result, Param> operation, 
			final Function<?, Result> chain) {
		
		return new Function<Result, Param>() {

			private final Function<?, Result> c = chain;
			private final Function<Result, Param> o = operation;
			
			@Override
			public Result call(Param par) {
				Result result = o.call(par);
				c.call(result);
				return result;
			}
		}; 
	}
	
	public static<Result, TransformParam, Param> Function<Result, Param> chain(
			final Function<TransformParam, Param> transform, 
			final Function<Result, TransformParam> operation) {
		
		return new Function<Result, Param>() {

			private final Function<TransformParam, Param>  t = transform;
			private final Function<Result, TransformParam> o = operation;
			
			@Override
			public Result call(Param par) {
				return o.call( t.call(par) );
			}
		}; 
	}
	
	public static<Result, Param> Function<Result, Param> prepareParam(
			final Function<?,   Param> operation1, 
			final Function<Result, Param> operation2) {
		
		return new Function<Result, Param>() {

			private final Function<?,   Param> o1 = operation1;
			private final Function<Result, Param> o2 = operation2;
			
			@Override
			public Result call(Param par) {
				o1.call(par);
				return o2.call(par);
			}
		}; 
	}
	
	public static<Result, Param> Function<Result, Param> prepareResult(
			final Function<Result, Param> operation2,
			final Function<?,   Result> operation1) {
		
		return new Function<Result, Param>() {

			private final Function<?,   Result> o1 = operation1;
			private final Function<Result, Param> o2 = operation2;
			
			@Override
			public Result call(Param par) {
				
				Result res = o2.call(par);
				o1.call(res);
				return res;
			}
		}; 
	}


	

	

	
	
}
